package com.p2p.common.utils;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.DecompressingHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * date: 2017.12.12
 *
 * @author: lizhuolun
 */
public abstract class HttpClientUtil {

    static final Logger log = LoggerFactory.getLogger(HttpClientUtil.class);

    public static final Charset UTF8 = Charset.forName("UTF-8");

    public static final Charset GB18030 = Charset.forName("GB18030");

    static final int TIME_OUT = Integer.getInteger("http.timeout", 40000);

    static final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.4 (KHTML, like Gecko) Safari/537.4";


    static HttpClient HTTP_CLIENT = bulidHttpClient();


    static HttpClient bulidHttpClient() {

        HttpClient client = null;
        try {
            client = HttpClientBuilder.create().build();
            client = new DecompressingHttpClient(client);
        } catch (Exception ex) {
            log.error("", ex);
        }

        return client;
    }


    public static String get(String url, Map<String, String> HEADERS)
            throws IOException {
        HttpGet get = new HttpGet(url);
        return execute(get, HEADERS, null);
    }

    public static String get(String url, Map<String, String> HEADERS,
                             Charset forceCharset) throws IOException {
        HttpGet get = new HttpGet(url);
        return execute(get, HEADERS, forceCharset);
    }

    public static String post(String url, Map<String, String> params,
                              Map<String, String> headers) throws IOException {
        HttpPost post = new HttpPost(url);// http请求类
        if (params != null && !params.isEmpty()) {// 判断了参数
            List<NameValuePair> ps = new ArrayList<NameValuePair>(params.size());
            for (Map.Entry<String, String> kv : params.entrySet()) {
                ps.add(new BasicNameValuePair(kv.getKey(), kv.getValue()));
            }
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(ps,
                    Consts.UTF_8);
            // entity.setContentEncoding("UTF-8");
            post.setEntity(entity);
        }
        return execute(post, headers, null);
    }

    public static String post(String url, Map<String, String> params,
                              Map<String, String> headers, String charsetName) throws IOException {
        HttpPost post = new HttpPost(url);// http请求类
        Charset charset = Charset.forName(charsetName);
        if (params != null && !params.isEmpty()) {// 判断了参数
            List<NameValuePair> ps = new ArrayList<NameValuePair>(params.size());
            for (Map.Entry<String, String> kv : params.entrySet()) {
                ps.add(new BasicNameValuePair(kv.getKey(), kv.getValue()));
            }

            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(ps, charset);
            // entity.setContentEncoding("UTF-8");
            post.setEntity(entity);
        }
        return execute(post, headers, charset);
    }

    public static <T> T http(HttpClient client, HttpRequestBase request,
                             Map<String, String> headers, HttpEntityHandler<T> handler)
            throws IOException {
        if (headers != null && !headers.isEmpty()) {
            for (Map.Entry<String, String> kv : headers.entrySet()) {
                request.addHeader(kv.getKey(), kv.getValue());
            }
        }
        long begin = System.currentTimeMillis();
        try {
            return client.execute(request, handler, null);
        } catch (ConnectTimeoutException e) {
            log.error(" catch ConnectTimeoutException ,closeExpiredConnections &  closeIdleConnections for 30 s. ");
            client.getConnectionManager().closeExpiredConnections();
            client.getConnectionManager().closeIdleConnections(30,
                    TimeUnit.SECONDS);
            throw e;
        } finally {
            log.info(handler.getName() + "  {},cost {} ms", request.getURI(),
                    System.currentTimeMillis() - begin);
        }
    }

    private static String execute(final HttpRequestBase request,
                                  Map<String, String> headers, final Charset forceCharset)
            throws IOException {
        return http(HTTP_CLIENT, request, headers,
                new HttpEntityHandler<String>() {
                    @Override
                    public String handle(HttpEntity entity) throws IOException {
                        if (entity == null) {
                            return null;
                        }
                        byte[] content = EntityUtils.toByteArray(entity);
                        if (forceCharset != null) {
                            return new String(content, forceCharset);
                        }
                        String html;
                        Charset charset = null;
                        ContentType contentType = ContentType.get(entity);
                        if (contentType != null) {
                            charset = contentType.getCharset();
                        }
                        if (charset == null) {
                            charset = HttpClientUtil.UTF8;
                        }
                        html = new String(content, charset);
                        charset = checkMetaCharset(html, charset);
                        if (charset != null) {
                            html = new String(content, charset);
                        }
                        return html;
                    }

                    public String getName() {
                        return request.getMethod();
                    }
                });
    }

    private static Charset checkMetaCharset(String html, Charset use) {
        String magic = "charset=";
        int index = html.indexOf(magic);
        if (index > 0 && index < 1000) {
            index += magic.length();
            int end = html.indexOf('"', index);
            if (end > index) {
                try {

                    String charSetString = html.substring(index, end)
                            .toLowerCase();

                    if (charSetString.length() > 10) {
                        return null;
                    }
                    // GBK GB2312 --> GB18030
                    if (charSetString.startsWith("gb")) {
                        return GB18030.equals(use) ? null : GB18030;
                    }
                    Charset curr = Charset.forName(charSetString);
                    if (!curr.equals(use)) {
                        return curr;
                    }
                } catch (Exception e) {
                    log.error("Get MetaCharset error", e);
                }
            }
        }

        return null;
    }


    public static void main(String[] args) throws Exception {


    }

}
